package com.dangs.autotest.ui;

import android.app.Instrumentation;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.PixelFormat;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ProgressBar;
import android.widget.TextView;


import com.dangs.autotest.R;
import com.dangs.autotest.activity.AutoTestActivity;
import com.dangs.autotest.system.PlatformAPI;
import com.dangs.autotest.test.TestManager;
import com.dangs.autotest.tool.L;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;

public class FloatView extends FrameLayout {
    final static String TAG = "FloatView";
    private WindowManager.LayoutParams mParams;
    private WindowManager mWindowManager;
    private int showFlag = FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR |
            FLAG_WATCH_OUTSIDE_TOUCH | FLAG_NOT_TOUCH_MODAL | FLAG_NOT_TOUCHABLE;
    private int hideFlag = FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_NOT_FOCUSABLE |
            FLAG_WATCH_OUTSIDE_TOUCH | FLAG_NOT_TOUCH_MODAL | FLAG_NOT_TOUCHABLE;
    private ExecutorService poolExecutor;
    private Handler handler;
    private ProgressBar progressBar;
    private Config config;
    private String realTime, cpuInfo, ramInfo, tempInfo, taskInfo;
    private TextView txInfo;

    private Runnable heartbeat = new Runnable() {
        @Override
        public void run() {
            if (poolExecutor != null) {
                poolExecutor.execute(() -> getUpdateInfo());
            }
            updateView();
            handler.postDelayed(this, 1000);
        }
    };

    private void updateView() {

        txInfo.setText("");
        if (config.isShowTime) {
            txInfo.append("TIME:" + realTime);
        }
        if (config.isShowCpu) {
            txInfo.append("\nCPU:" + cpuInfo);
        }
        if (config.isShowRam) {
            txInfo.append("\nRAM:" + ramInfo);
        }
        if (config.isShowTask) {
            txInfo.append("\nTASK:" + taskInfo);
        }
        if (config.isShowProgress) {
            progressBar.setProgress(TestManager.getInstance(getContext()).getProgress());
        }
    }

    private void getUpdateInfo() {
        realTime = PlatformAPI.getImp().getRealTime();
        cpuInfo = PlatformAPI.getImp().getCpuLoadRate();
        ramInfo = PlatformAPI.getImp().getRamInfo(getContext());
    }

    public FloatView(Context context) {
        super(context);
        poolExecutor = Executors.newSingleThreadExecutor();
        handler = new Handler(Looper.myLooper());
        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics displayMetrics = new DisplayMetrics();
        mWindowManager.getDefaultDisplay().getMetrics(displayMetrics);
        setTag("float view");
    }

    public void show(Config c) {
        if (c != null) {
            config = c;
        } else {
            config = new Config();
        }
        View layout = LayoutInflater.from(getContext()).inflate(R.layout.float_view_layout, this, false);
        layout.findViewById(R.id.tx_focus).setOnKeyListener((v, keycode, event) -> sendKey(v, keycode, event));
        addView(layout);
        progressBar = layout.findViewById(R.id.progress);
        if (config.isShowProgress) {
            progressBar.setVisibility(VISIBLE);
        } else {
            progressBar.setVisibility(INVISIBLE);
        }
        txInfo = layout.findViewById(R.id.tx_info);
        mParams = new WindowManager.LayoutParams();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {//SDK 26
            mParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            mParams.type = WindowManager.LayoutParams.TYPE_PHONE;
        }
        mParams.format = PixelFormat.RGBA_8888;
        mParams.flags = showFlag;
        mParams.gravity = config.gravity;
        mParams.width = WRAP_CONTENT;
        mParams.height = WRAP_CONTENT;
        mWindowManager.addView(this, mParams);
        handler.post(heartbeat);
    }

    public void hide() {
        handler.removeCallbacks(heartbeat);
        mWindowManager.removeView(this);
        L.d(TAG, "hide");
    }

    private boolean sendKey(View v, int keyCode, KeyEvent event) {
        L.d(TAG, "tag:" + v.getTag() + " onKey:" + event);
        if (event.getAction() == KeyEvent.ACTION_UP) {
            switch (keyCode) {
                case KeyEvent.KEYCODE_DPAD_CENTER:
                case KeyEvent.KEYCODE_DPAD_LEFT:
                case KeyEvent.KEYCODE_DPAD_UP:
                case KeyEvent.KEYCODE_DPAD_RIGHT:
                case KeyEvent.KEYCODE_DPAD_DOWN:
                case KeyEvent.KEYCODE_ENTER:
                case KeyEvent.KEYCODE_BACK:
                    poolExecutor.execute(() -> {
                        handler.post(() -> {
                            mParams.flags = hideFlag;
                            mWindowManager.updateViewLayout(this, mParams);
                        });
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            L.w(TAG, "sleep err");
                        }
                        new Instrumentation().sendKeyDownUpSync(keyCode);
                        handler.post(() -> {
                            mParams.flags = showFlag;
                            mWindowManager.updateViewLayout(this, mParams);
                        });
                    });
                    return true;
                case KeyEvent.KEYCODE_F6:
                    TestManager.getInstance().stop();
                    showActivity();
                    return true;
                case KeyEvent.KEYCODE_MENU:
                    break;
            }
        }
        return false;
    }

    private void showActivity() {
        getContext().startActivity(new Intent(getContext(), AutoTestActivity.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
        hide();
    }




    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        L.d(TAG, "finalize");
    }

    public static class Config implements Parcelable {
        public int gravity = Gravity.RIGHT | Gravity.TOP;
        public boolean isShowCpu = true;
        public boolean isShowFan = false;
        public boolean isShowProgress = true;
        public boolean isShowRam = true;
        public boolean isShowTask = true;
        public boolean isShowTime = true;
        public final static String KEY = "config";
        public final static String KEY_GRAVITY = "gravity";
        public final static String KEY_SHOW_CPU = "isShowCpu";
        public final static String KEY_SHOW_FAN = "isShowFan";
        public final static String KEY_SHOW_PROGRESS = "isShowProgress";
        public final static String KEY_SHOW_RAM = "isShowRam";
        public final static String KEY_SHOW_TASK = "isShowTask";

        public Config() {
        }

        public static void saveLocal(Context context, Config config) {
        }

        public int getViewSize () {
            int size = 0;
            if (isShowCpu) size++;
            if (isShowTime) size++;
            if (isShowProgress) size++;
            if (isShowFan) size++;
            if (isShowRam) size++;
            if (isShowTask) size++;
            return size;
        }

        public static Config getConfigFromLocal(Context context) {
            Config config = new Config();
            SharedPreferences sp = context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
            config.gravity = sp.getInt(KEY_GRAVITY, config.gravity);
            config.isShowCpu = sp.getBoolean(KEY_SHOW_CPU, config.isShowCpu);
            config.isShowFan = sp.getBoolean(KEY_SHOW_FAN, config.isShowFan);
            config.isShowProgress = sp.getBoolean(KEY_SHOW_PROGRESS, config.isShowProgress);
            config.isShowRam = sp.getBoolean(KEY_SHOW_RAM, config.isShowRam);
            config.isShowTask = sp.getBoolean(KEY_SHOW_TASK, config.isShowTask);
            return config;
        }

        public static void saveConfigIntoLocal(Context context, String key, Object value) {
            if (TextUtils.isEmpty(key)) {
                return;
            }
            L.d(TAG, "saveConfigIntoLocal:" + key + "->" + value);
            SharedPreferences.Editor editor =
                    context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE).edit();
            switch (key) {
                case KEY_GRAVITY:
                    editor.putInt(KEY_GRAVITY, (Integer) value);
                    break;
                case KEY_SHOW_CPU:
                    editor.putBoolean(KEY_SHOW_CPU, (Boolean) value);
                    break;
                case KEY_SHOW_FAN:
                    editor.putBoolean(KEY_SHOW_FAN, (Boolean) value);
                    break;
                case KEY_SHOW_PROGRESS:
                    editor.putBoolean(KEY_SHOW_PROGRESS, (Boolean) value);
                    break;
                case KEY_SHOW_RAM:
                    editor.putBoolean(KEY_SHOW_RAM, (Boolean) value);
                    break;
                case KEY_SHOW_TASK:
                    editor.putBoolean(KEY_SHOW_TASK, (Boolean) value);
                    break;
            }
            editor.commit();
            editor.clear();
        }


        protected Config(Parcel in) {
            gravity = in.readInt();
            isShowCpu = in.readByte() != 0;
            isShowFan = in.readByte() != 0;
            isShowProgress = in.readByte() != 0;
            isShowRam = in.readByte() != 0;
            isShowTask = in.readByte() != 0;
        }

        public static final Creator<Config> CREATOR = new Creator<Config>() {
            @Override
            public Config createFromParcel(Parcel in) {
                return new Config(in);
            }

            @Override
            public Config[] newArray(int size) {
                return new Config[size];
            }
        };

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeInt(gravity);
            dest.writeByte((byte) (isShowCpu ? 1 : 0));
            dest.writeByte((byte) (isShowFan ? 1 : 0));
            dest.writeByte((byte) (isShowProgress ? 1 : 0));
            dest.writeByte((byte) (isShowRam ? 1 : 0));
            dest.writeByte((byte) (isShowTask ? 1 : 0));
        }
    }
}
